1 package org.apache.lucene.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import java.util.Arrays;
21
22
23
24
25
26 public final class IntBlockPool {
27 public final static int INT_BLOCK_SHIFT = 13;
28 public final static int INT_BLOCK_SIZE = 1 << INT_BLOCK_SHIFT;
29 public final static int INT_BLOCK_MASK = INT_BLOCK_SIZE - 1;
30
31
32
33 public abstract static class Allocator {
34 protected final int blockSize;
35
36 public Allocator(int blockSize) {
37 this.blockSize = blockSize;
38 }
39
40 public abstract void recycleIntBlocks(int[][] blocks, int start, int end);
41
42 public int[] getIntBlock() {
43 return new int[blockSize];
44 }
45 }
46
47
48 public static final class DirectAllocator extends Allocator {
49
50
51
52
53 public DirectAllocator() {
54 super(INT_BLOCK_SIZE);
55 }
56
57 @Override
58 public void recycleIntBlocks(int[][] blocks, int start, int end) {
59 }
60 }
61
62
63 public int[][] buffers = new int[10][];
64
65
66 private int bufferUpto = -1;
67
68 public int intUpto = INT_BLOCK_SIZE;
69
70 public int[] buffer;
71
72 public int intOffset = -INT_BLOCK_SIZE;
73
74 private final Allocator allocator;
75
76
77
78
79
80 public IntBlockPool() {
81 this(new DirectAllocator());
82 }
83
84
85
86
87
88 public IntBlockPool(Allocator allocator) {
89 this.allocator = allocator;
90 }
91
92
93
94
95
96 public void reset() {
97 this.reset(true, true);
98 }
99
100
101
102
103
104
105
106
107
108
109 public void reset(boolean zeroFillBuffers, boolean reuseFirst) {
110 if (bufferUpto != -1) {
111
112
113 if (zeroFillBuffers) {
114 for(int i=0;i<bufferUpto;i++) {
115
116 Arrays.fill(buffers[i], 0);
117 }
118
119 Arrays.fill(buffers[bufferUpto], 0, intUpto, 0);
120 }
121
122 if (bufferUpto > 0 || !reuseFirst) {
123 final int offset = reuseFirst ? 1 : 0;
124
125 allocator.recycleIntBlocks(buffers, offset, 1+bufferUpto);
126 Arrays.fill(buffers, offset, bufferUpto+1, null);
127 }
128 if (reuseFirst) {
129
130 bufferUpto = 0;
131 intUpto = 0;
132 intOffset = 0;
133 buffer = buffers[0];
134 } else {
135 bufferUpto = -1;
136 intUpto = INT_BLOCK_SIZE;
137 intOffset = -INT_BLOCK_SIZE;
138 buffer = null;
139 }
140 }
141 }
142
143
144
145
146
147
148
149 public void nextBuffer() {
150 if (1+bufferUpto == buffers.length) {
151 int[][] newBuffers = new int[(int) (buffers.length*1.5)][];
152 System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
153 buffers = newBuffers;
154 }
155 buffer = buffers[1+bufferUpto] = allocator.getIntBlock();
156 bufferUpto++;
157
158 intUpto = 0;
159 intOffset += INT_BLOCK_SIZE;
160 }
161
162
163
164
165
166 private int newSlice(final int size) {
167 if (intUpto > INT_BLOCK_SIZE-size) {
168 nextBuffer();
169 assert assertSliceBuffer(buffer);
170 }
171
172 final int upto = intUpto;
173 intUpto += size;
174 buffer[intUpto-1] = 1;
175 return upto;
176 }
177
178 private static final boolean assertSliceBuffer(int[] buffer) {
179 int count = 0;
180 for (int i = 0; i < buffer.length; i++) {
181 count += buffer[i];
182 }
183 return count == 0;
184 }
185
186
187
188
189
190
191
192
193 private final static int[] NEXT_LEVEL_ARRAY = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9};
194
195
196
197
198 private final static int[] LEVEL_SIZE_ARRAY = {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
199
200
201
202
203 private final static int FIRST_LEVEL_SIZE = LEVEL_SIZE_ARRAY[0];
204
205
206
207
208 private int allocSlice(final int[] slice, final int sliceOffset) {
209 final int level = slice[sliceOffset];
210 final int newLevel = NEXT_LEVEL_ARRAY[level-1];
211 final int newSize = LEVEL_SIZE_ARRAY[newLevel];
212
213 if (intUpto > INT_BLOCK_SIZE-newSize) {
214 nextBuffer();
215 assert assertSliceBuffer(buffer);
216 }
217
218 final int newUpto = intUpto;
219 final int offset = newUpto + intOffset;
220 intUpto += newSize;
221
222 slice[sliceOffset] = offset;
223
224
225 buffer[intUpto-1] = newLevel;
226
227 return newUpto;
228 }
229
230
231
232
233
234
235
236 public static class SliceWriter {
237
238 private int offset;
239 private final IntBlockPool pool;
240
241
242 public SliceWriter(IntBlockPool pool) {
243 this.pool = pool;
244 }
245
246
247
248 public void reset(int sliceOffset) {
249 this.offset = sliceOffset;
250 }
251
252
253
254
255 public void writeInt(int value) {
256 int[] ints = pool.buffers[offset >> INT_BLOCK_SHIFT];
257 assert ints != null;
258 int relativeOffset = offset & INT_BLOCK_MASK;
259 if (ints[relativeOffset] != 0) {
260
261 relativeOffset = pool.allocSlice(ints, relativeOffset);
262 ints = pool.buffer;
263 offset = relativeOffset + pool.intOffset;
264 }
265 ints[relativeOffset] = value;
266 offset++;
267 }
268
269
270
271
272
273 public int startNewSlice() {
274 return offset = pool.newSlice(FIRST_LEVEL_SIZE) + pool.intOffset;
275
276 }
277
278
279
280
281
282
283
284 public int getCurrentOffset() {
285 return offset;
286 }
287 }
288
289
290
291
292
293 public static final class SliceReader {
294
295 private final IntBlockPool pool;
296 private int upto;
297 private int bufferUpto;
298 private int bufferOffset;
299 private int[] buffer;
300 private int limit;
301 private int level;
302 private int end;
303
304
305
306
307 public SliceReader(IntBlockPool pool) {
308 this.pool = pool;
309 }
310
311
312
313
314 public void reset(int startOffset, int endOffset) {
315 bufferUpto = startOffset / INT_BLOCK_SIZE;
316 bufferOffset = bufferUpto * INT_BLOCK_SIZE;
317 this.end = endOffset;
318 upto = startOffset;
319 level = 1;
320
321 buffer = pool.buffers[bufferUpto];
322 upto = startOffset & INT_BLOCK_MASK;
323
324 final int firstSize = IntBlockPool.LEVEL_SIZE_ARRAY[0];
325 if (startOffset+firstSize >= endOffset) {
326
327 limit = endOffset & INT_BLOCK_MASK;
328 } else {
329 limit = upto+firstSize-1;
330 }
331
332 }
333
334
335
336
337
338
339 public boolean endOfSlice() {
340 assert upto + bufferOffset <= end;
341 return upto + bufferOffset == end;
342 }
343
344
345
346
347
348 public int readInt() {
349 assert !endOfSlice();
350 assert upto <= limit;
351 if (upto == limit)
352 nextSlice();
353 return buffer[upto++];
354 }
355
356 private void nextSlice() {
357
358 final int nextIndex = buffer[limit];
359 level = NEXT_LEVEL_ARRAY[level-1];
360 final int newSize = LEVEL_SIZE_ARRAY[level];
361
362 bufferUpto = nextIndex / INT_BLOCK_SIZE;
363 bufferOffset = bufferUpto * INT_BLOCK_SIZE;
364
365 buffer = pool.buffers[bufferUpto];
366 upto = nextIndex & INT_BLOCK_MASK;
367
368 if (nextIndex + newSize >= end) {
369
370 assert end - nextIndex > 0;
371 limit = end - bufferOffset;
372 } else {
373
374
375 limit = upto+newSize-1;
376 }
377 }
378 }
379 }
380